/*
 * Copyright 2013 Sigurd Randoll.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.digiway.rapidbreeze.client.model.download;

import de.digiway.rapidbreeze.client.infrastructure.I18n;
import de.digiway.rapidbreeze.client.infrastructure.updatable.UpdatableEntry;
import de.digiway.rapidbreeze.shared.rest.download.DownloadResource;
import de.digiway.rapidbreeze.shared.rest.download.DownloadStatus;
import java.text.DecimalFormat;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import org.apache.commons.lang3.ObjectUtils;

/**
 * A bean model class having properties of a {@linkplain DownloadResource}.
 *
 * @author Sigurd
 */
public class DownloadModel implements UpdatableEntry<DownloadResource> {

    public static final String PROP_FILENAME = "filename";
    public static final String PROP_CLOUD_PROVIDER = "cloudProvider";
    public static final String PROP_PROGRESS = "progress";
    public static final String PROP_ETA = "eta";
    public static final String PROP_STATUS = "status";
    public static final String PROP_TRANSLATED_STATUS = "translatedStatus";
    public static final String PROP_IDENTIFIER = "identifier";
    private StringProperty filename = new SimpleStringProperty();
    private StringProperty cloudProvider = new SimpleStringProperty();
    private DoubleProperty progress = new SimpleDoubleProperty();
    private StringProperty eta = new SimpleStringProperty();
    private ObjectProperty<DownloadStatus> status = new SimpleObjectProperty();
    private StringProperty translatedStatus = new SimpleStringProperty();
    private String identifier;
    private static final DecimalFormat speedFormat = new DecimalFormat("#,##0.00");
    private I18n i18n = I18n.getInstance();

    /**
     * Creates a new instance based on the given {@linkplain DownloadResource}.
     * Properties are copied from the object to the resource.
     *
     * @param resource
     */
    public DownloadModel(DownloadResource resource) {
        this.identifier = resource.getIdentifier();
        this.filename.setValue(resource.getFilename());
        this.cloudProvider.setValue(resource.getCloudProvider());
        this.progress.setValue(resource.getProgress());
        this.eta.setValue(getEtaString(resource));
        this.status.setValue(resource.getDownloadStatus());
        this.translatedStatus.setValue(translateStatus(getStatus()));
    }

    private String getEtaString(DownloadResource resource) {
        return formatEta(resource.getEta()) + " (" + speedFormat.format(resource.getKiloBytesPerSecond()) + " kb/s)";
    }

    private String formatEta(long seconds) {
        long min = TimeUnit.SECONDS.toMinutes(seconds);
        long sec = seconds - TimeUnit.MINUTES.toSeconds(min);
        return String.format("%02d:%02d Min", min, sec);
    }

    /**
     * Updates this bean by checking each property of the given
     * {@linkplain DownloadResource} and apply new value if necessary.
     *
     * @param resource
     */
    @Override
    public void update(DownloadResource resource) {
        if (resource == null || !resource.getIdentifier().equals(identifier)) {
            throw new IllegalArgumentException(DownloadResource.class.getSimpleName() + " must not be null and must have same identifier as original object.");
        }

        if (!ObjectUtils.equals(resource.getFilename(), getFilename())) {
            filename.setValue(resource.getFilename());
        }
        if (!ObjectUtils.equals(resource.getCloudProvider(), getCloudProvider())) {
            cloudProvider.setValue(resource.getCloudProvider());
        }
        if (!ObjectUtils.equals(resource.getProgress(), getProgress())) {
            progress.setValue(resource.getProgress());
        }
        if (!ObjectUtils.equals(resource.getEta(), getEta())) {
            eta.setValue(getEtaString(resource));
        }
        if (!ObjectUtils.equals(resource.getDownloadStatus(), getStatus())) {
            status.setValue(resource.getDownloadStatus());
            translatedStatus.setValue(translateStatus(getStatus()));
        }
    }

    public String getFilename() {
        return filename.get();
    }

    public String getCloudProvider() {
        return cloudProvider.get();
    }

    public Double getProgress() {
        return progress.doubleValue();
    }

    public String getEta() {
        return eta.get();
    }

    public DownloadStatus getStatus() {
        return status.get();
    }

    public boolean isRunning() {
        return DownloadStatus.RUNNING.equals(getStatus());
    }

    public boolean isFinished() {
        return DownloadStatus.FINISHED_SUCCESSFUL.equals(getStatus());
    }

    public boolean isError() {
        return DownloadStatus.ERROR.equals(getStatus());
    }

    public boolean isPause() {
        return DownloadStatus.PAUSE.equals(getStatus());
    }

    public boolean isWaiting() {
        return DownloadStatus.WAITING.equals(getStatus());
    }

    public String getTranslatedStatus() {
        return translatedStatus.get();
    }

    private String translateStatus(DownloadStatus status) {
        return i18n.getResourceBundle().getString("DownloadStatus." + status.toString());
    }

    @Override
    public String getIdentifier() {
        return identifier;
    }

    public StringProperty filenameProperty() {
        return filename;
    }

    public StringProperty etaProperty() {
        return eta;
    }

    public DoubleProperty progressProperty() {
        return progress;
    }

    public StringProperty cloudProviderProperty() {
        return cloudProvider;
    }

    public ObjectProperty<DownloadStatus> statusProperty() {
        return status;
    }

    public StringProperty translatedStatusProperty() {
        return translatedStatus;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 37 * hash + Objects.hashCode(this.identifier);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final DownloadModel other = (DownloadModel) obj;
        if (!Objects.equals(this.identifier, other.identifier)) {
            return false;
        }
        return true;
    }
}
